local Debug = false

-- 用于子级协程yieldreturn时寻找父级协程
local yield_map = {}
-- 协程数据缓存池
local yield_pool = {}
-- 协程缓存池
local co_pool = {}

-- 回收协程
local function __RecycleCoroutine(co)
	if not coroutine.status(co) == "suspended" then
		error("Try to recycle coroutine not suspended : "..coroutine.status(co))
	end
	
	table.insert(co_pool, co)
end

-- 可复用协程
local function __Coroutine(func, ...)
	local args = SafePack(...)
	while func do
		local ret = SafePack(func(SafeUnpack(args)))
		__RecycleCoroutine(coroutine.running())
		args = SafePack(coroutine.yield(SafeUnpack(ret)))
		func = args[1]
		table.remove(args, 1)
	end
end

-- 获取协程
local function __GetCoroutine()
	local co = nil
	if table.length(co_pool) > 0 then
		co = table.remove(co_pool)
	else
		co = coroutine.create(__Coroutine)
	end
	return co
end

-- 协程运行在保护模式下，不会抛出异常，所以这里要捕获一下异常
-- 但是可能会遇到调用协程时对象已经被销毁的情况，这种情况应该被当做正常情况
-- 所以这里并不继续抛出异常，而只是输出一下错误日志，不要让客户端当掉
-- 注意：Logger中实际上在调试模式会抛出异常
local function __PResume(co, func, ...)
	local resume_ret = nil
	if func ~= nil then
		resume_ret = SafePack(coroutine.resume(co, func, ...))
	else
		resume_ret = SafePack(coroutine.resume(co, ...))
	end
	local flag, msg = resume_ret[1], resume_ret[2]
	if not flag then
		print(msg.."\n"..debug.traceback(co))
	elseif resume_ret.n > 1 then
		table.remove(resume_ret, 1)
	else
		resume_ret = nil
	end
	return flag, resume_ret
end

-- 启动一个协程：等待协程第一次让出控制权时主函数继续往下执行，这点表现和Unity协程一致
-- 等同于Unity侧的StartCoroutine
-- @func：协程函数体
-- @...：传入协程的可变参数
local function start(func, ...)
	local co = __GetCoroutine()
	__PResume(co, func, ...)
	return co
end

coroutine.start = start
coroutine.yieldcallback = yieldcallback
coroutine.yieldbreak = yieldbreak

-- 调试用：查看内部状态
if Debug then
	return{
		yield_map = yield_map,
		yield_pool = yield_pool,
		co_pool = co_pool,
	}
end